package com.google.code.gronono.gps.ui.panels.pages.tree;

import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.log4j.Logger;

import com.google.code.gronono.commons.exif.ExifData;
import com.google.code.gronono.commons.exif.ExifUtils;
import com.google.code.gronono.commons.i18n.BundleKey;
import com.google.code.gronono.commons.i18n.BundleName;
import com.google.code.gronono.commons.io.file.jpeg.JpegFile;
import com.google.code.gronono.gps.model.Configuration;
import com.google.code.gronono.gps.model.SortedFile;

/**
 * Arbre spécifique à l'application,
 * implémentant notamment la méthode {@link #getToolTipText(MouseEvent)}.
 */
@BundleName(value = "com.google.code.gronono.gps.gui")
public class SortedFileTree extends JTree {
	/** serialVersionUID. */
	private static final long serialVersionUID = 3157183115829229168L;
	/** Logger. */
	private static final Logger logger = Logger.getLogger(SortedFileTree.class);

	/** Formatage des dates pour les tooltip pour les fichier de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.date.format")
	private static String TOOLTIP_DATE_FORMAT;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.line.break")
	private static String TOOLTIP_LINE_BREAK;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.sep")
	private static String TOOLTIP_SEP;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.tab")
	private static String TOOLTIP_TAB;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.start")
	private static String TOOLTIP_START;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.start.file")
	private static String TOOLTIP_START_FILE;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.start.folder")
	private static String TOOLTIP_START_FOLDER;
	/** Tooltip pour les fichiers sources de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.src.file.path")
	private static String TOOLTIP_SRC_FILE_PATH;
	/** Tooltip pour les fichiers sources de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.src.file.lastmod")
	private static String TOOLTIP_SRC_FILE_LASTMOD;
	/** Tooltip pour les fichiers cibles de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.dst.file.path")
	private static String TOOLTIP_DST_FILE_PATH;
	/** Tooltip pour les fichiers cibles de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.dst.file.create")
	private static String TOOLTIP_DST_FILE_CREATE;
	/** Tooltip pour les fichiers cibles de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.dst.file.lastmod")
	private static String TOOLTIP_DST_FILE_LASTMOD;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.err.msg")
	private static String TOOLTIP_ERR_MSG;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.err.cause")
	private static String TOOLTIP_ERR_CAUSE;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.exif")
	private static String TOOLTIP_EXIF;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.exif.src")
	private static String TOOLTIP_EXIF_SRC;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.exif.dst")
	private static String TOOLTIP_EXIF_DST;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.exif.orientation")
	private static String TOOLTIP_EXIF_ORIENTATION;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.exif.orientation.rotate")
	private static String TOOLTIP_EXIF_ORIENTATION_ROTATE;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.exif.date")
	private static String TOOLTIP_EXIF_DATE;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.exif.thumbnail")
	private static String TOOLTIP_EXIF_THUMBNAIL;
	/** Tooltip pour les fichiers de l'arbre. */
	@BundleKey(value = "result.page.file.tooltip.end")
	private static String TOOLTIP_END;

	/** La configuration de l'application. */
	private final Configuration configuration;
	/** Flag indiquant si l'arbre concerné est l'arbre source. */
	private boolean isSrcTree;
	/** Formateur pour l'affichage des dates. */
	private static SimpleDateFormat df;

	/**
	 * Constructeur.
	 * @param configuration La configuration de l'application.
	 * @param isSrcTree Flag indiquant si l'arbre concerné est l'arbre source.
	 */
	public SortedFileTree(final Configuration configuration, final boolean isSrcTree) {
		super();
		this.configuration = configuration;
		this.isSrcTree = isSrcTree;
		if (df == null) df = new SimpleDateFormat(TOOLTIP_DATE_FORMAT);
	}

	/* (non-Javadoc)
	 * @see javax.swing.JTree#getToolTipText(java.awt.event.MouseEvent)
	 */
	@Override
	public String getToolTipText(final MouseEvent e) {
		// Récupération du chemin associé à l'événement
		final TreePath path = getPathForLocation(e.getX(), e.getY());
		if (path != null) {
			// Récupération du noeud, datamodel et fichiers correspondant
			final DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent();
			final SortedFile sortedFile = (SortedFile) selectedNode.getUserObject();
			final File srcFile = sortedFile.getSrcFile();
			final File dstFile = sortedFile.getDstFile();

			final boolean isSrcFile = (srcFile != null) && srcFile.isFile();

			// Construction du tooltip
			final StringBuilder tooltip = new StringBuilder();
			if (!isSrcFile) tooltip.append(MessageFormat.format(TOOLTIP_START, TOOLTIP_START_FOLDER));
			else tooltip.append(MessageFormat.format(TOOLTIP_START, TOOLTIP_START_FILE));
			tooltip.append(TOOLTIP_LINE_BREAK);

			// Informations sur le fichier source
			if (isSrcFile || isSrcTree) {
				tooltip.append(TOOLTIP_SRC_FILE_PATH).append(TOOLTIP_SEP).append(srcFile.getAbsolutePath());
				tooltip.append(TOOLTIP_LINE_BREAK).append(TOOLTIP_TAB).append(TOOLTIP_SRC_FILE_LASTMOD).append(TOOLTIP_SEP).append(df.format(new Date(srcFile.lastModified())));
				tooltip.append(TOOLTIP_LINE_BREAK);
			}

			// Informations sur le fichier cible éventuel
			if (dstFile != null) {
				if (isSrcFile || isSrcTree) tooltip.append(TOOLTIP_LINE_BREAK); // Cas des dossiers pour l'arbre cible
				tooltip.append(TOOLTIP_DST_FILE_PATH);
				if (!dstFile.exists()) tooltip.append(TOOLTIP_DST_FILE_CREATE);
				tooltip.append(TOOLTIP_SEP).append(dstFile.getAbsolutePath());
				if (dstFile.exists()) tooltip.append(TOOLTIP_LINE_BREAK).append(TOOLTIP_TAB).append(TOOLTIP_DST_FILE_LASTMOD).append(TOOLTIP_SEP).append(df.format(new Date(dstFile.lastModified())));
				tooltip.append(TOOLTIP_LINE_BREAK);
			}

			// Informations sur l'erreur éventuelle
			if (StringUtils.isNotBlank(sortedFile.getErrorMsg())) {
				tooltip.append(TOOLTIP_LINE_BREAK).append(TOOLTIP_ERR_MSG).append(TOOLTIP_SEP).append(sortedFile.getErrorMsg());
				if (StringUtils.isNotBlank(sortedFile.getErrorCause())) {
					tooltip.append(TOOLTIP_LINE_BREAK).append(TOOLTIP_TAB).append(TOOLTIP_ERR_CAUSE).append(TOOLTIP_SEP).append(sortedFile.getErrorCause());
				}
				tooltip.append(TOOLTIP_LINE_BREAK);
			}

			// Informations sur les données exif éventuelles
			if ((srcFile != null) && srcFile.isFile()) {
				ExifData exifData = null;
				boolean isSrcExifData = true;
				if ((dstFile != null) && !isSrcTree) {
					final JpegFile jpegDstFile = new JpegFile(dstFile);
					exifData = jpegDstFile.getExifData();
				}
				if (exifData == null) {
					final JpegFile jpegSrcFile = new JpegFile(srcFile);
					exifData = jpegSrcFile.getExifData();
				} else isSrcExifData = false;
				if (exifData != null) {
					tooltip.append(TOOLTIP_LINE_BREAK).append(TOOLTIP_EXIF);
					if (isSrcExifData) tooltip.append(TOOLTIP_EXIF_SRC);
					else tooltip.append(TOOLTIP_EXIF_DST);
					tooltip.append(TOOLTIP_SEP);
					// Date de prise de vue
					if (exifData.getDate() != null) {
						tooltip.append(TOOLTIP_LINE_BREAK).append(TOOLTIP_TAB).append(TOOLTIP_EXIF_DATE).append(TOOLTIP_SEP).append(df.format(exifData.getDate()));
					}
					// Orientation
					if (exifData.getOrientation() != null) {
						tooltip.append(TOOLTIP_LINE_BREAK).append(TOOLTIP_TAB).append(TOOLTIP_EXIF_ORIENTATION).append(TOOLTIP_SEP).append(exifData.getOrientationDescr());
						if (configuration.isRotate() && ExifUtils.needsRotation(exifData.getOrientation())) tooltip.append(TOOLTIP_EXIF_ORIENTATION_ROTATE);
					}
					// Thumbnail
					if (exifData.getThumbnail() != null) {
						// Ecriture temporaire du fichier dans io.tmpdir pour affichage
						final StringBuilder tmpDirPath = new StringBuilder(SystemUtils.JAVA_IO_TMPDIR).append(File.separator).append("gps");
						final StringBuilder thumbnailPath = new StringBuilder(tmpDirPath).append(File.separator).append("thumb_").append(srcFile.getName());
						logger.trace("Thumbnail : " + thumbnailPath + " (" + exifData.getThumbnail().length/1024 + " Ko)");
						final File tmpDir = new File(tmpDirPath.toString());
						final File thumb = new File(thumbnailPath.toString());
						try {
							if (!tmpDir.exists()) tmpDir.mkdirs();
							// Rmq: remplacement systématique du thumbnail pr le cas où la conf a changé ('redresser' activé puis désactivé par ex.)
							if (thumb.exists()) FileUtils.deleteQuietly(thumb);
							final FileOutputStream fos = new FileOutputStream(thumbnailPath.toString());
							if (configuration.isRotate()) fos.write(exifData.getRotatedThumbnail());
							else fos.write(exifData.getThumbnail());
							fos.close();
						} catch (final Exception ex) {
							logger.error("Exception : " + ex.getMessage() + (ex.getCause() != null ? ", cause : " + ex.getCause() : ""), ex);
						} finally {
							if (thumb.exists()) {
								tooltip.append(TOOLTIP_LINE_BREAK).append(TOOLTIP_TAB).append(TOOLTIP_EXIF_THUMBNAIL).append(TOOLTIP_SEP);
								tooltip.append("<img align=\"top\" src=\"file:&#47;&#47;&#47;&#47;").append(thumbnailPath.toString().replace(File.separator, "&#47;&#47;")).append("\" &#47;>");
								tooltip.append(TOOLTIP_LINE_BREAK);
								thumb.deleteOnExit();
							}
						}
					}
				}
			}

			tooltip.append(TOOLTIP_LINE_BREAK);
			tooltip.append(TOOLTIP_END);

			return tooltip.toString();
		}

		return null;
	}

}
